package smtpserver

import (
	"context"
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/nosch/smtpoll/logger"
	"github.com/panjf2000/gnet/v2"
)

// GnetConnAdapter 适配 gnet.Conn 到 Connection 接口
type GnetConnAdapter struct {
	conn gnet.Conn
}

func (a *GnetConnAdapter) Read(b []byte) (int, error) {
	return a.conn.Read(b)
}

func (a *GnetConnAdapter) Write(b []byte) (int, error) {
	return a.conn.Write(b)
}

func (a *GnetConnAdapter) Close() error {
	return a.conn.Close()
}

func (a *GnetConnAdapter) RemoteAddr() net.Addr {
	return a.conn.RemoteAddr()
}

func (a *GnetConnAdapter) LocalAddr() net.Addr {
	return a.conn.LocalAddr()
}

func (a *GnetConnAdapter) SetReadDeadline(t time.Time) error {
	return a.conn.SetReadDeadline(t)
}

func (a *GnetConnAdapter) SetWriteDeadline(t time.Time) error {
	return a.conn.SetWriteDeadline(t)
}

func (a *GnetConnAdapter) SetDeadline(t time.Time) error {
	return a.conn.SetDeadline(t)
}

// GnetReaderAdapter 将 gnet.Conn 适配为 io.Reader
type GnetReaderAdapter struct {
	conn gnet.Conn
}

func NewGnetReaderAdapter(conn gnet.Conn) *GnetReaderAdapter {
	return &GnetReaderAdapter{conn: conn}
}

func (a *GnetReaderAdapter) Read(p []byte) (n int, err error) {
	buf, _ := a.conn.Next(len(p))
	if len(buf) == 0 {
		return 0, nil
	}
	n = copy(p, buf)
	return n, nil
}

// GnetSmtpServer gnet 实现的服务器
type GnetSmtpServer struct {
	options    *ServerOptions
	handler    MessageHandler
	eng        *gnet.Engine
	sessionMap sync.Map
	stopCh     chan struct{} // 用于通知停止接受新连接
}

const DefaultHostname = "localhost"

// NewGnetSmtpServer 创建新的 gnet 服务器
func NewGnetSmtpServer(options *ServerOptions, handler MessageHandler) *GnetSmtpServer {
	return &GnetSmtpServer{
		options: options,
		handler: handler,
		stopCh:  make(chan struct{}),
	}
}

// Run 运行服务器
func (s *GnetSmtpServer) Run() error {
	if s.options == nil {
		return fmt.Errorf("server options is nil")
	}

	// 为每个端口创建监听器
	for _, port := range s.options.Ports {
		addr := fmt.Sprintf("%s:%d", s.options.Host, port)
		logger.LogInfo(context.Background(), "Creating gnet listener", "addr", addr)

		// 创建 gnet 引擎
		eng := &gnet.Engine{}
		s.eng = eng

		// 启动引擎
		go func(e *gnet.Engine, a string) {
			opts := []gnet.Option{
				gnet.WithMulticore(true),
				gnet.WithTCPKeepAlive(time.Minute * 5),
				gnet.WithTCPNoDelay(gnet.TCPNoDelay),
			}
			if err := gnet.Run(s, "tcp://"+a, opts...); err != nil {
				logger.LogError(context.Background(), "Error running gnet engine", "addr", a, "error", err)
			}
		}(eng, addr)
	}

	return nil
}

// OnBoot 当服务器启动时调用
func (s *GnetSmtpServer) OnBoot(eng gnet.Engine) gnet.Action {
	return gnet.None
}

// OnShutdown 当服务器关闭时调用
func (s *GnetSmtpServer) OnShutdown(eng gnet.Engine) {
	logger.LogInfo(context.Background(), "Gnet server shutting down")
}

// OnOpen 当新连接建立时调用
func (s *GnetSmtpServer) OnOpen(c gnet.Conn) (out []byte, action gnet.Action) {
	select {
	case <-s.stopCh:
		return nil, gnet.Close
	default:
		remoteAddr := c.RemoteAddr()
		localAddr := c.LocalAddr()
		if remoteAddr == nil || localAddr == nil {
			logger.LogError(context.Background(), "Invalid connection addresses")
			return nil, gnet.Close
		}

		logger.LogInfo(context.Background(), "New connection established",
			"remote_addr", remoteAddr.String(),
			"local_addr", localAddr.String())

		// 创建适配器
		adapter := &GnetConnAdapter{conn: c}
		if adapter == nil {
			logger.LogError(context.Background(), "Failed to create connection adapter")
			return nil, gnet.Close
		}

		// 创建会话
		session := NewSession(adapter, s.handler, NewDefaultAuthSource())
		if session == nil {
			logger.LogError(context.Background(), "Failed to create session")
			return nil, gnet.Close
		}

		// 存储会话
		s.sessionMap.Store(c, session)

		return nil, gnet.None
	}
}

// OnClose 当连接关闭时调用
func (s *GnetSmtpServer) OnClose(c gnet.Conn, err error) (action gnet.Action) {
	if session, ok := s.sessionMap.LoadAndDelete(c); ok {
		if s, ok := session.(*Session); ok {
			logger.LogInfo(s.ctx, "Connection closed",
				"remote_addr", c.RemoteAddr().String(),
				"error", err)
		}
	}
	return gnet.None
}

// OnTraffic 当收到数据时调用
func (s *GnetSmtpServer) OnTraffic(c gnet.Conn) (action gnet.Action) {
	select {
	case <-s.stopCh:
		return gnet.Close
	default:
		value, ok := s.sessionMap.Load(c)
		if !ok {
			logger.LogError(context.Background(), "Session not found for connection", "remote_addr", c.RemoteAddr().String())
			return gnet.Close
		}

		session := value.(*Session)
		reader := NewGnetReaderAdapter(c)
		if err := session.ProcessConnection(reader); err != nil {
			logger.LogError(session.ctx, "Session processing failed", "error", err)
			s.sessionMap.Delete(c)
			return gnet.Close
		}

		return gnet.None
	}
}

// OnTick 定时器回调
func (s *GnetSmtpServer) OnTick() (delay time.Duration, action gnet.Action) {
	return time.Second, gnet.None
}

// Stop 停止服务器
func (s *GnetSmtpServer) Stop() error {
	logger.LogInfo(context.Background(), "Starting server shutdown")

	// 1. 首先通知停止接受新连接
	close(s.stopCh)

	// 2. 关闭所有活动连接
	s.sessionMap.Range(func(key, value any) bool {
		if conn, ok := key.(gnet.Conn); ok {
			if session, ok := value.(*Session); ok {
				logger.LogInfo(session.ctx, "Closing connection during shutdown",
					"remote_addr", conn.RemoteAddr().String())
				// 发送关闭消息
				session.respond(CODE_BYE, "Server shutting down")
				// 关闭连接
				conn.Close()
			}
		}
		return true
	})

	// 3. 关闭引擎
	if s.eng != nil {
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()

		if err := gnet.Stop(ctx, "tcp://"+s.options.Host+":"+fmt.Sprintf("%d", s.options.Ports[0])); err != nil {
			logger.LogError(ctx, "Failed to stop gnet engine", "error", err)
		}
	}

	logger.LogInfo(context.Background(), "Server shutdown completed")
	return nil
}

// GetOptions 返回服务器配置选项
func (s *GnetSmtpServer) GetOptions() *ServerOptions {
	return s.options
}
